package main

import (
	"encoding/csv"
	"fmt"
	"gitee.com/libbylg/pkgr/repo"
	"os"
	"sort"
	"strings"
)

// CmdListOptions 定义了 list 子命令的所有可能选型
//
//	thpkg list [LABEL]
type CmdListOptions struct {
	Filter *repo.ModuleLabelFilter

	Format     string // 格式化方式
	FormatArgs string // 格式化参数
	ShowHeader bool   // 是否显示表头
}

// NewCmdListOptions 识别命令行选项.
// pkgr list [PATTERN] [--regex] [--plan PLAN-FILE] [--env ENV-NAME] [--devrepo|--pkgrepo] [--csv [SEP]]
func NewCmdListOptions(argv []string) (*CmdListOptions, error) {
	if len(argv) < 2 {
		return nil, fmt.Errorf("the required parameter is missing, try -h for help")
	}

	// 初始化默认值
	opt := &CmdListOptions{
		Filter:     repo.NewModuleLabelFilter(),
		ShowHeader: true,
		Format:     "",
		FormatArgs: "",
	}

	// 读取选项
	for index := 2; index < len(argv); index++ {
		// 是否按照正则表达式的方式去匹配
		if argv[index] == "--regex" {
			opt.Filter.Regex = true
			continue
		}

		// 指定 plan file 场景
		if argv[index] == "--plan" {
			if len(opt.Filter.PlanFile) != 0 {
				return nil, fmt.Errorf("the install plan file has been specified with `%v'", opt.Filter.PlanFile)
			}

			if index+1 >= len(argv) {
				return nil, fmt.Errorf("the option `%v' is missing value", argv[index])
			}

			index++
			opt.Filter.PlanFile = argv[index]
			continue
		}

		// 指定 plan env 场景
		if argv[index] == "--view" {
			if len(opt.Filter.PlanView) != 0 {
				return nil, fmt.Errorf("the plan env has been specified with `%v'", opt.Filter.PlanView)
			}

			if index+1 >= len(argv) {
				return nil, fmt.Errorf("the option `%v' is missing value", argv[index])
			}

			index++
			opt.Filter.PlanView = argv[index]
			continue
		}

		if argv[index] == "--devrepo" {
			if opt.Filter.WhichRepo != "" {
				continue
			}
			opt.Filter.WhichRepo = "devrepo"
			continue
		}

		if argv[index] == "--pkgrepo" {
			if opt.Filter.WhichRepo != "" {
				continue
			}
			opt.Filter.WhichRepo = "pkgrepo"
			continue
		}

		if argv[index] == "--no-header" {
			opt.ShowHeader = false
			continue
		}

		if argv[index] == "--csv" {
			opt.Format = "csv"
			if (index+1) >= len(argv) || strings.HasPrefix(argv[index+1], "-") {
				opt.FormatArgs = ","
				continue
			}

			index++
			opt.FormatArgs = argv[index]
			continue
		}

		// 遇到无法识别的选项
		if strings.HasPrefix(argv[index], "-") {
			return nil, fmt.Errorf("unsupported options `%v'", argv[index])
		}

		// 识别 PATTERN 参数
		if len(opt.Filter.Pattern) == 0 {
			opt.Filter.Pattern = argv[index]
			continue
		}

		return nil, fmt.Errorf("unsupported option `%v'", argv[index])
	}

	// 整理
	opt.Filter.Tidy("devrepo")

	if opt.Format == "" || opt.Format == "default" {
		opt.Format = "default"
		opt.FormatArgs = ""
		opt.ShowHeader = false
	}

	return opt, nil
}

type ListColumns struct {
	Label *repo.ModuleLabel

	// 依赖于PKGREPO的字段
	ImportAs           string
	TrainVersion       string
	TrainModuleName    string
	TrainModuleVersion string
	License            string
	Description        string
	StatusVersioned    string

	// 依赖于plan的字段
	Usages        string
	Views         string
	StatusPlanned string

	// 依赖于DEVREPO的字段
	StatusInstalled string
}

func NewListColumns(label *repo.ModuleLabel) *ListColumns {
	return &ListColumns{
		Label: label,

		ImportAs:           "",
		TrainVersion:       "",
		TrainModuleName:    "",
		TrainModuleVersion: "",
		License:            "",
		Description:        "",
		StatusVersioned:    "-",

		Usages:        "",
		Views:         "",
		StatusPlanned: "-",

		StatusInstalled: "-",
	}
}

// CmdList 用例按照给定的条件列出模块信息.
func CmdList(argv []string) int {
	// 加载选项
	opt, err := NewCmdListOptions(argv)
	if err != nil {
		ERROR("Load option for `%v' failed: %v", "list", err.Error())
		return 1
	}

	// 筛选需要显示的列表
	moduleLabelList, err := repo.SelectModuleLabels(opt.Filter)
	if err != nil {
		ERROR("Filter modules failed: %v", err.Error())
		return 1
	}

	// 排序
	sort.Slice(moduleLabelList[:], func(i, j int) bool {
		return moduleLabelList[i].String() < moduleLabelList[j].String()
	})

	// 默认的输出方式
	if opt.Format == "default" {
		for _, item := range moduleLabelList {
			fmt.Fprintf(os.Stdout, "%v\n", item.String())
		}
		return 0
	}

	// 按CSV格式输出
	if opt.Format == "csv" {
		// 读取installplan文件
		var installPlan *repo.InstallPlan = nil
		if opt.Filter.PlanFile != "" {
			installPlan, _ = repo.ReadInstallPlanFile(opt.Filter.PlanFile, false)
		}

		// 所有待显示行
		allRows := make([]*ListColumns, 0, len(moduleLabelList))

		// 显示表格内容
		for _, moduleLabel := range moduleLabelList {
			cols := NewListColumns(moduleLabel)

			// 依赖于 module-version 文件的信息
			if repo.PathIsDir(repo.PKGREPO) {
				detial, err := repo.ReadModuleVersionDescription(moduleLabel.String())
				if err != nil {
					WARNI("Load module version file for `%v' failed: %v", moduleLabel.String(), err)
					continue
				}

				//cols.ImportAs = detial.ImportAs
				//cols.TrainVersion = detial.TrainVersion
				//cols.TrainModuleName = detial.TrainModuleName
				//cols.TrainModuleVersion = detial.TrainModuleVersion
				//cols.License = detial.License
				cols.Description = detial.Description
				cols.StatusVersioned = "v"
			}

			// 依赖于plan文件的信息
			if installPlan != nil {
				planItem, exist := installPlan.Find(moduleLabel.String())
				if exist {
					cols.Usages = repo.JoinSet(planItem.Usages)
					cols.Views = repo.JoinSet(planItem.Views)
					cols.StatusPlanned = "p"
				}
			}

			// 依赖于安装后的信息
			if repo.PathIsDir(repo.DEVREPO) {
				if repo.IsInstalled(moduleLabel.ModuleName, moduleLabel.ModuleVersion) {
					cols.StatusInstalled = "i"
				}
			}

			// 保存收集到的信息
			allRows = append(allRows, cols)
		}

		// 准备输出
		writer := csv.NewWriter(os.Stdout)
		writer.Comma = rune(opt.FormatArgs[0])

		// 标题
		titles := []string{"#MODULE", "LABEL", "STATUS", "VIEWS", "USAGES", "IMPORTAS", "TRAINVERSION", "TRAINMODULENAME", "TRAINMODULEVERSION", "LICENSE", "DESCRIPTION"}

		// 显示标题
		if opt.ShowHeader {
			writer.Write(titles)
			writer.Flush()
		}

		for _, cols := range allRows {
			records := make([]string, 0, len(titles))
			records = append(records, "MODULE")
			records = append(records, cols.Label.String())
			records = append(records, cols.StatusVersioned+cols.StatusPlanned+cols.StatusInstalled)
			records = append(records, cols.Views)
			records = append(records, cols.Usages)
			records = append(records, cols.ImportAs)
			records = append(records, cols.TrainVersion)
			records = append(records, cols.TrainModuleName)
			records = append(records, cols.TrainModuleVersion)
			records = append(records, cols.License)
			records = append(records, cols.Description)
			writer.Write(records)
		}

		writer.Flush()

		return 0
	}

	ERROR("Unsupported output format `%v'", opt.Format)
	return 1
}
